// main.go
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strings"

	alidns20150109 "github.com/alibabacloud-go/alidns-20150109/v4/client"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	util "github.com/alibabacloud-go/tea-utils/v2/service"
	"github.com/alibabacloud-go/tea/tea"
	credential "github.com/aliyun/credentials-go/credentials"
	"github.com/gin-gonic/gin"
)

// AliDNSClient 阿里云DNS客户端结构体
type AliDNSClient struct {
	client *alidns20150109.Client
}

// NewAliDNSClient 创建新的阿里云DNS客户端
func NewAliDNSClient() (*AliDNSClient, error) {

	// 工程代码建议使用更安全的无AK方式，凭据配置方式请参见：https://help.aliyun.com/document_detail/378661.html。
	myCredential, err := credential.NewCredential(nil)
	if err != nil {
		return nil, err
	}

	config := &openapi.Config{
		Credential: myCredential,
		Endpoint:   tea.String("alidns.aliyuncs.com"),
	}

	client, err := alidns20150109.NewClient(config)
	if err != nil {
		return nil, err
	}

	return &AliDNSClient{client: client}, nil
}

// GetDomainRecords 获取域名解析记录
func (dns *AliDNSClient) GetDomainRecords(domain, rr, rrType string) ([]*alidns20150109.DescribeDomainRecordsResponseBodyDomainRecordsRecord, error) {
	describeDomainRecordsRequest := &alidns20150109.DescribeDomainRecordsRequest{
		DomainName: tea.String(domain),
		RRKeyWord:  tea.String(rr),
		Type:       tea.String(rrType),
		Status:     tea.String("Enable"),
	}

	runtime := &util.RuntimeOptions{}
	result, err := dns.client.DescribeDomainRecordsWithOptions(describeDomainRecordsRequest, runtime)
	if err != nil {
		return nil, handleAPIError(err)
	}

	return result.Body.DomainRecords.Record, nil
}

// UpdateDomainRecord 更新域名解析记录
func (dns *AliDNSClient) UpdateDomainRecord(recordId, rr, rrType, value string) error {
	updateDomainRecordRequest := &alidns20150109.UpdateDomainRecordRequest{
		RecordId: tea.String(recordId),
		RR:       tea.String(rr),
		Type:     tea.String(rrType),
		Value:    tea.String(value),
	}

	runtime := &util.RuntimeOptions{}
	_, err := dns.client.UpdateDomainRecordWithOptions(updateDomainRecordRequest, runtime)
	if err != nil {
		return handleAPIError(err)
	}

	return nil
}

// AddDomainRecord 添加域名解析记录
func (dns *AliDNSClient) AddDomainRecord(domain, rr, rrType, value string) error {
	addDomainRecordRequest := &alidns20150109.AddDomainRecordRequest{
		DomainName: tea.String(domain),
		RR:         tea.String(rr),
		Type:       tea.String(rrType),
		Value:      tea.String(value),
	}

	runtime := &util.RuntimeOptions{}
	_, err := dns.client.AddDomainRecordWithOptions(addDomainRecordRequest, runtime)
	if err != nil {
		return handleAPIError(err)
	}

	return nil
}

// handleAPIError 处理API错误
func handleAPIError(err error) error {
	var sdkErr *tea.SDKError
	ok := errors.As(err, &sdkErr)
	if !ok {
		return err
	}

	// 打印错误详情
	log.Printf("API Error: %s\n", tea.StringValue(sdkErr.Message))

	// 解析错误数据中的推荐信息
	var data interface{}
	if sdkErr.Data != nil {
		d := json.NewDecoder(strings.NewReader(tea.StringValue(sdkErr.Data)))
		if d.Decode(&data) == nil {
			if m, ok := data.(map[string]interface{}); ok {
				if recommend, exists := m["Recommend"]; exists {
					log.Printf("Recommendation: %v\n", recommend)
				}
			}
		}
	}

	return err
}

// DDNSHandler DDNS请求处理函数
func DDNSHandler(c *gin.Context) {
	domain := c.Query("domain")
	rr := c.Query("rr")
	rrType := c.Query("rrType")
	ip := c.Query("ip")

	// 参数校验
	if domain == "" || rr == "" || rrType == "" || ip == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "缺少必要的参数: domain, rr, rrType, ip",
		})
		return
	}

	// 创建DNS客户端
	dnsClient, err := NewAliDNSClient()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("Failed to create DNS client: %v", err),
		})
		return
	}

	// 获取现有记录
	records, err := dnsClient.GetDomainRecords(domain, rr, rrType)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("Failed to get domain records: %v", err),
		})
		return
	}

	var message string
	if len(records) > 0 {
		record := records[0]
		// 检查IP是否发生变化
		if *record.Value == ip {
			message = "IP地址不变，无需更新"
		} else {
			// 更新记录
			err = dnsClient.UpdateDomainRecord(*record.RecordId, rr, rrType, ip)
			if err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{
					"error": fmt.Sprintf("Failed to update domain record: %v", err),
				})
				return
			}
			message = "IP地址已更改，域记录已更新"
		}
	} else {
		// 添加新记录
		err = dnsClient.AddDomainRecord(domain, rr, rrType, ip)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"error": fmt.Sprintf("Failed to add domain record: %v", err),
			})
			return
		}
		message = "未找到现有记录，已添加新记录"
	}

	// 返回成功响应
	c.JSON(http.StatusOK, gin.H{
		"message": message,
		"domain":  domain,
		"rr":      rr,
		"type":    rrType,
		"ip":      ip,
	})
}

func main() {
	// 设置为发布模式（生产环境）
	gin.SetMode(gin.ReleaseMode)

	r := gin.Default()

	// 注册路由
	r.GET("/ddns", DDNSHandler)

	// 启动服务器
	log.Println("Starting DDNS server on :80")
	if err := r.Run(":80"); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
